package model;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.GregorianCalendar;
import java.util.List;

/**
 * 
 * @author Csaba Tarkanyi
 * 
 */
public class SparePart extends Object implements Comparable<SparePart> {
	// Part of the Strategy Pattern.
	private Comparator<SparePart> comparator;

	private long uniqueID;
	private long storageID;
	private long drawID;
	private long boxID;
	private String name;
	private int unit;
	private int presetLimit;
	private int avgDeliveryTime;
	private String specialNote;

	// link: SparePart 1-->0...* SparePartHistory
	private List<SparePartHistory> sparePartHistories;

	/**
	 * 
	 * @param uniqueID -
	 *            the 7 unique digits of SparePart (Require: only numbers.)
	 * @param storageID -
	 *            here: 3 digits of storage
	 * @param drawID -
	 *            here: 3 digits of draw
	 * @param boxID -
	 *            here: 3 digits of box
	 * @param name -
	 *            of the SparePart
	 * @param unit -
	 *            quantity of the SparePart
	 * @param presetLimit -
	 *            is the limit, how many SparePart should be on stock
	 * @param avgDeliveryTime -
	 *            is the average time of delivery in days
	 * @param specialNote -
	 *            special note for SpecialTool of SparePart or for anything else
	 * 
	 * @author Csaba Tarkanyi
	 */
	public SparePart(long uniqueID, long storageID, long drawID, long boxID,
			String name, int unit, int presetLimit, int avgDeliveryTime,
			String specialNote) {
		this.uniqueID = uniqueID;
		this.storageID = storageID;
		this.drawID = drawID;
		this.boxID = boxID;
		this.name = name;
		this.unit = unit;
		this.presetLimit = presetLimit;
		this.avgDeliveryTime = avgDeliveryTime;
		this.specialNote = specialNote;

		sparePartHistories = new ArrayList<SparePartHistory>();
	}

	/**
	 * @return the uniqueID
	 * 
	 * @author Csaba Tarkanyi
	 */
	public long getUniqueID() {
		return uniqueID;
	}

	/**
	 * @param uniqueID
	 *            the uniqueID to set
	 * 
	 * @author Csaba Tarkanyi
	 */
	public void setUniqueID(long uniqueID) {
		this.uniqueID = uniqueID;
	}

	/**
	 * @return the storageID
	 * 
	 * @author Csaba Tarkanyi
	 */
	public long getStorageID() {
		return storageID;
	}

	/**
	 * @param storageID
	 *            the storageID to set
	 * 
	 * @author Csaba Tarkanyi
	 */
	public void setStorageID(long storageID) {
		this.storageID = storageID;
	}

	/**
	 * @return the drawID
	 * 
	 * @author Csaba Tarkanyi
	 */
	public long getDrawID() {
		return drawID;
	}

	/**
	 * @param drawID
	 *            the drawID to set
	 * 
	 * @author Csaba Tarkanyi
	 */
	public void setDrawID(long drawID) {
		this.drawID = drawID;
	}

	/**
	 * @return the boxID
	 * 
	 * @author Csaba Tarkanyi
	 */
	public long getBoxID() {
		return boxID;
	}

	/**
	 * @param boxID
	 *            the boxID to set
	 * 
	 * @author Csaba Tarkanyi
	 */
	public void setBoxID(long boxID) {
		this.boxID = boxID;
	}

	/**
	 * @return the name
	 * 
	 * @author Csaba Tarkanyi
	 */
	public String getName() {
		return name;
	}

	/**
	 * @param name
	 *            the name to set
	 * 
	 * @author Csaba Tarkanyi
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * @return the unit
	 * 
	 * @author Csaba Tarkanyi
	 */
	public int getUnit() {
		return unit;
	}

	/**
	 * @param unit
	 *            the unit to set
	 * 
	 * @author Csaba Tarkanyi
	 */
	public void setUnit(int unit) {
		this.unit = unit;
	}

	/**
	 * @return the presetLimit
	 * 
	 * @author Csaba Tarkanyi
	 */
	public int getPresetLimit() {
		return presetLimit;
	}

	/**
	 * @param presetLimit
	 *            the presetLimit to set
	 * 
	 * @author Csaba Tarkanyi
	 */
	public void setPresetLimit(int presetLimit) {
		this.presetLimit = presetLimit;
	}

	/**
	 * @return the avgDeliveryTime
	 * 
	 * @author Csaba Tarkanyi
	 */
	public int getAvgDeliveryTime() {
		return avgDeliveryTime;
	}

	/**
	 * @param avgDeliveryTime
	 *            the avgDeliveryTime to set
	 * 
	 * @author Csaba Tarkanyi
	 */
	public void setAvgDeliveryTime(int avgDeliveryTime) {
		this.avgDeliveryTime = avgDeliveryTime;
	}

	/**
	 * @return the specialNote
	 * 
	 * @author Csaba Tarkanyi
	 */
	public String getSpecialNote() {
		return specialNote;
	}

	/**
	 * @param specialNote
	 *            the specialNote to set
	 * 
	 * @author Csaba Tarkanyi
	 */
	public void setSpecialNote(String specialNote) {
		this.specialNote = specialNote;
	}

	// Strategy Pattern start

	/**
	 * Sets Comparator of the SparePart.
	 * 
	 * @author Csaba Tarkanyi
	 */
	public void setComparator(Comparator<SparePart> comparator) {
		this.comparator = comparator;
	}

	/**
	 * Comparing this SparePart to the parameter SparePart.
	 * 
	 * @author Csaba Tarkanyi
	 */
	@Override
	public int compareTo(SparePart o) {
		SparePart sp = (SparePart) o;
		return comparator.compare(this, sp);
	}

	// Strategy Pattern end

	// Link-Methods start

	/**
	 * Adds a SparePartHistory.
	 * 
	 * @author Csaba Tarkanyi
	 */
	public void addSparePartHistory(SparePartHistory sph) {
		sparePartHistories.add(sph);
	}

	/**
	 * Removes a SparePartHistory.
	 * 
	 * @author Csaba Tarkanyi
	 */
	public void removeSparePartHistory(SparePartHistory sph) {
		sparePartHistories.remove(sph);
	}

	/**
	 * @return to a List of SparePartHistories.
	 * 
	 * @author Csaba Tarkanyi
	 */
	public List<SparePartHistory> getSparePartHistories() {
		return sparePartHistories;
	}

	/**
	 * Creates a new SparePartHistory with the current date, Reparation and
	 * SparePartUse.
	 * 
	 * @param reparation -
	 *            the SparePartHistory belongs to this Reparation.
	 * 
	 * @param sparePartUse -
	 *            contains the quantity and the SparePart for this
	 *            SparePartHistory.
	 * 
	 * @author Csaba Tarkanyi
	 */
	public void createSparePartHistory(Reparation reparation,
			SparePartUse sparePartUse) {
		SparePartHistory sph = new SparePartHistory(new GregorianCalendar(),
				reparation, sparePartUse);
		// Adds the history to the Reparation only if it is not null.
		if (reparation != null) {
			reparation.addSparePartHistory(sph);
		} else {
			sparePartHistories.add(sph);
		}
	}

	// Link-Methods end

	// Other-Methods start

	/**
	 * Calculates the monthly use of SparePart according to the parameter.
	 * <br />
	 * Require: date != null.
	 * 
	 * @param date -
	 *            the given "condition date"
	 * 
	 * @author Csaba Tarkanyi
	 */
	public int getMonthlyUseOfSparePart(GregorianCalendar date) {
		int used = 0;
		/*
		 * For-each loop for getting all the SparePartHistory one by one.
		 */
		for (SparePartHistory sph : sparePartHistories) {
			/*
			 * If the SparePartHistory's date fits to the "condition date" than
			 * adds the SparePart unit to the used integer.
			 */
			if (sph.getDate().get(GregorianCalendar.MONTH) == date
					.get(GregorianCalendar.MONTH)
					&& sph.getDate().get(GregorianCalendar.YEAR) == date
							.get(GregorianCalendar.YEAR)) {
				used += sph.getSparePartUse().getQuantity();
			}
		}
		return used;
	}

	/**
	 * Gets the biggest use of a SparePart between two dates by counting the use
	 * for each month within the interval of the two dates.
	 * 
	 * @param start -
	 *            is the startDate
	 * @param end -
	 *            is the endDate
	 * @return to the biggest use of a SparePart
	 * 
	 * @author Csaba Tarkanyi
	 */
	public int getMonthlyUseOfSparePart(GregorianCalendar start,
			GregorianCalendar end) {
		/*
		 * To store the biggest monthly use of a SparePart between the 2 dates.
		 */
		int max = 0;
		/*
		 * While the startDate is smaller than the endDate or the years and the
		 * months are the same for both of the dates, it saves the monthly use
		 * of SparePart if it is bigger than the max value and increases the
		 * startDate by 1 month.
		 */
		while (start.before(end)
				|| (start.get(GregorianCalendar.YEAR) == end
						.get(GregorianCalendar.YEAR) && start
						.get(GregorianCalendar.MONTH) == end
						.get(GregorianCalendar.MONTH))) {
			// Saves the monthly use of the SparePart.
			int current = getMonthlyUseOfSparePart(start);
			// Checks is it bigger than the max.
			if (current > max) {
				max = current;
			}
			// Increases the startDate by 1 month.
			start.add(GregorianCalendar.MONTH, 1);
		}
		return max;
	}

	// Other-Methods end

	/**
	 * Returns to a String with the necessary parameters, what we want to see.<br />
	 * 
	 * This toString method overrides the inherited toString method from the
	 * Object class.
	 * 
	 * @author Csaba Tarkanyi
	 */
	@Override
	public String toString() {
		return uniqueID + " " + storageID + " " + drawID + " " + boxID + " "
				+ name + " " + unit + " " + presetLimit + " " + avgDeliveryTime
				+ " " + specialNote;
	}
}